package com.xli.dto.component.model;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.xli.dto.component.TreeNode;
import com.xli.dto.component.model.query.Query;
import com.xli.dto.component.serializer.ModelSerializer;
import com.xli.dto.component.util.TreeUtil;
import com.xli.dto.search.SearchDTO;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;

import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@JsonSerialize(using = ModelSerializer.class)
public abstract class TableTreeModel<V, E, D extends SearchDTO> extends Query<E, D> {

    private final Map<Long,TreeNode<V>> data;

    private final D dto;
    private final int current;
    private final int pageSize;

    private final Map<Long, List<TreeNode<V>>> children;


    public TableTreeModel(D dto) {
        this.dto = dto;
        this.current = dto.getCurrent();
        this.pageSize = dto.getPageSize();
        this.data = new HashMap<>();

        List<TreeNode<V>> tempList = this.fetch(0, Integer.MAX_VALUE);
        this.children = tempList.stream()
                .collect(Collectors.groupingBy(treeNode -> Optional.ofNullable(treeNode.getPid()).orElse(TreeUtil.defaultPid)));

        for (TreeNode<V> treeNode : tempList) {
            this.data.put(treeNode.getId(),treeNode);
            TreeUtil.buildTree(treeNode, this::fetchChild, this.data);
        }
    }

    public abstract List<TreeNode<V>> fetch(int current, int pageSize);

    public List<TreeNode<V>> fetchChild(TreeNode<V> treeNode) {
        if (this.children.containsKey(treeNode.getId())) {
            return this.children.get(treeNode.getId());
        }
        return new ArrayList<>();
    }


    public QueryWrapper<E> getQueryWrapper() {
        return this.buildQueryWrapper(dto);
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append("{").append("\"total\":").append(this.data.size()).append(",")
                .append("\"list\":").append("[");

        List<TreeNode<V>> nodeList = new ArrayList<>(data.values());
        List<TreeNode<V>> list = CollUtil.page(current - 1, pageSize, nodeList);

        for (int i = 0; i < list.size(); i++) {
            TreeNode<V> treeNode = list.get(i);
            sb.append(treeNode.toString());
            if (i < list.size() - 1) {
                sb.append(",");
            }
        }
        sb.append("]}");
        return sb.toString();
    }
}
